
import { isSimilarTo } from "./util";
import SymbolFactorEntity from "../module/symbol-factor/SymbolFactor.entity";
import { MergeData } from "./DataHandler";
import { debugLogger, outLogger } from "../common/logger";
import { MixIndicatorsTolerance } from "./types";
import { Period } from "./PeriodProcess";
import { SimilarityMetrics } from "./SimilarityMetrics";

export interface SymbolFactor<T = number[]> {
  label?: number;
  vectors?: T;
  time: Date;
}


const equal = (a: number, b: number) => a == b

const comparisonHandlers = [
  equal,
  equal,
  equal,
  isSimilarTo, // change_rate_15m
  isSimilarTo, // close_ma_rate_15m
  isSimilarTo, // close_ma_rate_4h
  isSimilarTo, // close_ma_rate_1d
  isSimilarTo, // volume_rate_15m
  isSimilarTo, // volume_rate_4h
  isSimilarTo, // volume_rate_1d
  isSimilarTo, // exceptional_undulation_rate_15m
  isSimilarTo, // exceptional_undulation_rate_4h
  isSimilarTo, // exceptional_undulation_rate_1d
]
export class Statistics {
  static isSimilarity(
    current_feature_vector: number[],
    sample_feature_vector: number[],
    rateRange: number[], fault_conut = 0,
  ) {
    const len = sample_feature_vector.length;
    const comparisonList: boolean[] = []
    const detail = []
    for (let i = 0; i < len; i++) {
      const current_value = current_feature_vector[i];
      const sample_value = sample_feature_vector[i];

      const comparison = comparisonHandlers[i];
      if (comparison) {     
        // detail.push({ current_value, sample_value, range: rateRange[i], comparison: comparison(current_value, sample_value, rateRange[i]) })
        comparisonList.push(comparison(current_value, sample_value, rateRange[i]))
      }
    }
    // console.log(detail)
    const result = comparisonList.filter(v => v === true).length >= comparisonList.length - fault_conut;

    return result && comparisonList.length > 0;
  }
  static jsonToVectors(feature_vector_detail: MixIndicatorsTolerance) {
    return [
      feature_vector_detail.slope_15m,
      feature_vector_detail.slope_4h,
      feature_vector_detail.slope_1d,

      feature_vector_detail.change_rate_15m,

      feature_vector_detail.close_ma_rate_15m,
      feature_vector_detail.close_ma_rate_4h,
      feature_vector_detail.close_ma_rate_1d,
      
      feature_vector_detail.volume_rate_15m,
      feature_vector_detail.volume_rate_4h,
      feature_vector_detail.volume_rate_1d,

      feature_vector_detail.exceptional_undulation_rate_15m,
      feature_vector_detail.exceptional_undulation_rate_4h,
      feature_vector_detail.exceptional_undulation_rate_1d,
    ]
  }
  static vectorsToJson(vectors: (number | string)[], symbol: string) {
    const [
      slope_15m,
      slope_4h,
      slope_1d,

      change_rate_15m,
      close_ma_rate_15m,
      close_ma_rate_4h,
      close_ma_rate_1d,
      volume_rate_15m,
      volume_rate_4h,
      volume_rate_1d,
      exceptional_undulation_rate_15m,
      exceptional_undulation_rate_4h,
      exceptional_undulation_rate_1d,
      ...others
    ] = vectors;

    if (others.length > 0) {
      outLogger.error(`数据还有(${symbol})`, others)
    }
    return {
      // 状态
      slope_15m: Number(slope_15m),
      slope_4h: Number(slope_4h),
      slope_1d: Number(slope_1d),

      // 比率
      change_rate_15m: Number(change_rate_15m),
      close_ma_rate_15m: Number(close_ma_rate_15m),
      close_ma_rate_4h: Number(close_ma_rate_4h),
      close_ma_rate_1d: Number(close_ma_rate_1d),
      volume_rate_15m: Number(volume_rate_15m),
      volume_rate_4h: Number(volume_rate_4h),
      volume_rate_1d: Number(volume_rate_1d),
      exceptional_undulation_rate_15m: Number(exceptional_undulation_rate_15m),
      exceptional_undulation_rate_4h: Number(exceptional_undulation_rate_4h),
      exceptional_undulation_rate_1d: Number(exceptional_undulation_rate_1d),
    } as Omit<MixIndicatorsTolerance, 'vector_stort_15m'>
  }

  symbolVectors: Record<string, (SymbolFactor[])> = {};
  constructor() {
    this.symbolVectors = {};
  }

  vectorSimilarityCunstom = (bar: MergeData, period: Period, feature_vector: number[], rateRange: number[], fault_conut = 0) => {

    const symbolShortVectors = this.getVectors(bar.symbol, period)

    // 检查key是否匹配
    const lastSymbolVector = symbolShortVectors[symbolShortVectors.length - 1];

    if (feature_vector.length !== lastSymbolVector.vectors.length) {
      console.warn(`feature_vector.length !== lastSymbolVector.vectors.length`)
    }

    for (let i = symbolShortVectors.length - 1; i > 0; i--) {
      const symbolVector = symbolShortVectors[i];
      const result = Statistics.isSimilarity(feature_vector, symbolVector.vectors, rateRange, fault_conut);
      if (result) {
        return symbolVector
      }
    }
  }
  vectorSimilarityCosin = (bar: MergeData, period: Period, feature_vector: number[], similarity_target = 0.985) => {
    const symbolShortVectors = this.getVectors(bar.symbol, period)

    for (let i = symbolShortVectors.length - 1; i > 0; i--) {
      const symbolVector = symbolShortVectors[i];
      const similarity = SimilarityMetrics.cosineSimilarity(symbolVector.vectors, feature_vector);
      if (similarity > similarity_target) {
        return symbolVector;
      }
    }
  }

  vectorSimilarityManhattan = (bar: MergeData, period: Period, feature_vector: number[], similarity_target = 2.1) => {
    const symbolShortVectors = this.getVectors(bar.symbol, period)

    for (let i = symbolShortVectors.length - 1; i > 0; i--) {
      const symbolVector = symbolShortVectors[i];
      const similarity = SimilarityMetrics.manhattanDistance(symbolVector.vectors, feature_vector);
      if (similarity < similarity_target) {
        return symbolVector;
      }
    }
  }
  getVectors(symbol: string, period: Period) {

    if (!this.symbolVectors[`${symbol}-${period}`]) {
      debugLogger(`this.getVectors[${`${symbol}-${period}`}] undefined`, true);
      return [];
    }
    return this.symbolVectors[`${symbol}-${period}`] || []
  }
  setVectors(symbol: string, period: Period, list: SymbolFactorEntity[] | SymbolFactor[]) {
    if (!Array.isArray(list) || list.length === 0) {
      return
    }

    if ((list as SymbolFactorEntity[])[0].feature_vector) {
      this.symbolVectors[`${symbol}-${period}`] = (list as SymbolFactorEntity[]).map(({feature_vector, ...other}) => {
        return {
          ...other,
          vectors: feature_vector.map(item => Number(item))
        }
      });
      return
    } else if ((list as SymbolFactor[])[0].vectors) {

      this.symbolVectors[`${symbol}-${period}`] = list
    } else {
      debugLogger(`setVectors[${symbol}-${period}] undefined`);
    }
  }
  clearVectors(symbol: string, period: Period) {
    this.symbolVectors[`${symbol}-${period}`] = [];
  }
  destroy() {
    this.symbolVectors = {};
  }
}

export const sample = new Statistics();
